﻿using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;

namespace DesktopToyWpf.Views;

public enum ResizeDirection
{
    Left,
    Right
}

public class ResizeBorderWindow : Window
{
    public static void Setup(Window parent, ResizeDirection direction, double size = 8d)
    {
        new ResizeBorderWindow(parent, direction, size).Show();
    }

    private readonly double Size;
    private IntPtr Handle;
    private IntPtr ParentHandle;

    public ResizeBorderWindow(Window parent, ResizeDirection direction, double size)
    {
        ShowInTaskbar = false;
        WindowStyle = WindowStyle.None;
        ResizeMode = ResizeMode.NoResize;
        AllowsTransparency = true;
        ShowActivated = false;
        Focusable = false;

        Owner = parent;
        Size = size;

        var brush = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); 
        // var brush = new SolidColorBrush(Colors.Red); // 调试时使用的颜色
        brush.Freeze();
        Background = brush;

        ParentWindow = parent;
        ResizeDirection = direction;

        Cursor = direction switch
        {
            ResizeDirection.Left => Cursors.SizeWE,
            ResizeDirection.Right => Cursors.SizeWE,
            _ => Cursors.Arrow
        };

        Width = Size;
        Height = Size;

        Loaded += OnLoaded;
    }

    private readonly Window ParentWindow;
    private readonly ResizeDirection ResizeDirection;
    private DpiScale ThisDpi;
    private DpiScale ParentDpi;

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        ParentWindow.StateChanged += ParentWindow_OnStateChanged;
        ParentWindow.LocationChanged += ParentWindow_OnLocationChanged;
        ParentWindow.Activated += ParentWindow_OnActivated;
        ParentWindow.DpiChanged += ParentWindowOnDpiChanged;
        ParentWindow.SizeChanged += ParentWindow_OnSizeChanged;
        DpiChanged += OnDpiChanged;

        Handle = new WindowInteropHelper(this).Handle;
        ParentHandle = new WindowInteropHelper(ParentWindow).Handle;
        var source = HwndSource.FromHwnd(Handle);
        if (source == null) return;
        source.AddHook(WndProc);
    }

    private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
    {
        const int WM_MOUSEACTIVATE = 0x0021;
        const int NA_NOACTIVATE = 3;

        // 禁止窗口激活
        if (msg == WM_MOUSEACTIVATE)
        {
            handled = true;
            return new IntPtr(NA_NOACTIVATE);
        }

        return IntPtr.Zero;
    }

    private void ParentWindow_OnActivated(object? sender, EventArgs e) => Follow();

    private void ParentWindow_OnLocationChanged(object? sender, EventArgs e) => Follow();

    private void ParentWindow_OnStateChanged(object? sender, EventArgs e) => Follow();

    private void OnLoaded(object sender, RoutedEventArgs e) => UpdateDpi();

    private void OnDpiChanged(object sender, DpiChangedEventArgs e) => UpdateDpi();

    private void ParentWindow_OnSizeChanged(object sender, SizeChangedEventArgs e) => Follow();

    private void ParentWindowOnDpiChanged(object sender, DpiChangedEventArgs e) => UpdateDpi();

    private void UpdateDpi()
    {
        ThisDpi = VisualTreeHelper.GetDpi(this);
        ParentDpi = VisualTreeHelper.GetDpi(ParentWindow);
        Follow();
    }

    private void Follow()
    {
        var parentRect = new Rect(ParentWindow.PointToScreen(new Point(0, 0)), ParentWindow.PointToScreen((Point)ParentWindow.RenderSize));
        var parentRectPixel = new Rect(parentRect.Left * ThisDpi.DpiScaleX, parentRect.Top * ThisDpi.DpiScaleY, parentRect.Width * ThisDpi.DpiScaleX, parentRect.Height * ThisDpi.DpiScaleY);
        var sizePixel = (int)(Size * ThisDpi.DpiScaleX);

        switch (ResizeDirection)
        {
            case ResizeDirection.Left:
                Utils.SetWindowPos(Handle, IntPtr.Zero,
                    (int)(parentRectPixel.Left / ThisDpi.DpiScaleX) - sizePixel,
                    (int)(parentRectPixel.Top / ThisDpi.DpiScaleY),
                    sizePixel,
                    (int)(parentRectPixel.Height / ThisDpi.DpiScaleY),
                    Utils.SWP_NOACTIVATE | Utils.SWP_NOZORDER | Utils.SWP_NOREDRAW);

                break;
            case ResizeDirection.Right:
                Utils.SetWindowPos(Handle, IntPtr.Zero,
                    (int)(parentRectPixel.Right / ThisDpi.DpiScaleX),
                    (int)(parentRectPixel.Top / ThisDpi.DpiScaleY),
                    sizePixel,
                    (int)(parentRectPixel.Height / ThisDpi.DpiScaleY),
                    Utils.SWP_NOACTIVATE | Utils.SWP_NOZORDER | Utils.SWP_NOREDRAW);
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        if (e.Handled) return;
        e.Handled = true;

        Utils.ResizeWindow(ParentHandle, ResizeDirection switch
        {
            ResizeDirection.Left => Utils.WMSZ_LEFT,
            ResizeDirection.Right => Utils.WMSZ_RIGHT,
            _ => throw new ArgumentOutOfRangeException()
        });
    }
}